﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Resources;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using PokeData;

namespace PokeTD_MapEditor {
    public partial class Form1 : Form {

        #region Map-Data
        struct Field {
            public int x;
            public int y;
        }

        PictureBox selectedTile;
        string name;
        int money;
        Field _startfield = new Field();
        Field _endfield = new Field();
        byte[,] _Fields;
        int MapHeight {
            get { return _Fields.GetLength(0); }
        }
        int MapWidth {
            get { return _Fields.GetLength(1); }
        }
        #endregion

        bool ctrlPressed = false;
        bool altPressed = false;
        string mapPath = "";
        bool mapOpened;
        bool disclaimerShown = false;

        WavesDS wds = new WavesDS();
        TilesetDS tds = new TilesetDS();

        TowerEdit twEdit;
        CreepEdit crEdit;
        WaveEdit wvEdit;

        bool twEditOpen = false;
        bool crEditOpen = false;
        bool wvEditOpen = false;

        public Form1() {
            InitializeComponent();
        }

        private void pb_Click(object sender, EventArgs e) {
            selectedTile = (PictureBox)sender;
            if (Form.ActiveForm == this) pnlTileset.Focus();
        }

        private void pnlTileset_MouseEnter(object sender, System.EventArgs e) {
            if (Form.ActiveForm == this) pnlTileset.Focus();
        }



        private void pnlMap_MouseEnter(object sender, System.EventArgs e) {
            if (Form.ActiveForm == this) pnlMap.Focus();
        }

        private void picMap_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
            if (e.Button == MouseButtons.Left) {
                int x = (e.X / 32);
                int y = (e.Y / 32);
                if (x < 0 || y < 0 || x >= MapWidth || y >= MapHeight) return;
                if (ctrlPressed && !altPressed && (x != _endfield.x || y != _endfield.y)) {
                    txtStartX.Text = "" + x;
                    txtStartY.Text = "" + y;
                } else if (!ctrlPressed && altPressed && (x != _startfield.x || y != _startfield.y)) {
                    txtEndX.Text = "" + x;
                    txtEndY.Text = "" + y;
                } else {
                    if (selectedTile != null) {
                        setTile(selectedTile, x, y);
                    }
                    if (x == _startfield.x && y == _startfield.y) {
                        setStartField(x, y);
                    }
                    if (x == _endfield.x && y == _endfield.y) {
                        setEndField(x, y);
                    }
                }
                picMapPreview.Image = picMap.Image;
                Graphics g = Graphics.FromImage(picMap.Image);
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
                drawGrid(g);
                picMap.Refresh();
            }
        }
        private void picMap_MouseEnter(object sender, System.EventArgs e) {
            if (Form.ActiveForm == this) pnlMap.Focus();
        }

        private void checkCtrlAlt(object sender, System.Windows.Forms.KeyEventArgs e) {
            ctrlPressed = e.Control;
            altPressed = e.Alt;
        }

        private void picMap_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
            picMap_MouseMove(sender, e);
        }

        private void drawMap() {
            int height = _Fields.GetLength(0);
            int width = _Fields.GetLength(1);
            Bitmap b = new Bitmap(width * 32, height * 32);
            Graphics g = Graphics.FromImage(b);
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    if (_Fields[y, x] < pnlTileset.Controls.Count) {
                        Image tile = ((PictureBox)pnlTileset.Controls[_Fields[y, x]]).Image;
                        g.DrawImage(tile, new Rectangle(x * 32, y * 32, 32, 32), 0, 0, tile.Width, tile.Height, GraphicsUnit.Pixel);
                    } else {
                        _Fields[y, x] = 0;
                    }
                }
            }
            g.FillRectangle(new SolidBrush(Color.FromArgb(95, Color.Green)), _startfield.x * 32, _startfield.y * 32, 32, 32);
            g.FillRectangle(new SolidBrush(Color.FromArgb(95, Color.Red)), _endfield.x * 32, _endfield.y * 32, 32, 32);

            picMapPreview.Image = new Bitmap(b);

            drawGrid(g);

            picMap.Image = b;
            picMap.Height = height * 32;
            picMap.Width = width * 32;

        }
        private void drawGrid(Graphics g) {
            for (int i = 1; i < MapWidth; i++) {
                g.DrawLine(Pens.Gray, i * 32, 0, i * 32, MapHeight * 32);
            }

            for (int i = 1; i < MapHeight; i++) {
                g.DrawLine(Pens.Gray, 0, i * 32, MapWidth * 32, i * 32);
            }
        }

        private void mnuMapLaden_Click(object sender, EventArgs e) {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "Map (*.map)|*.map";
            if (dlg.ShowDialog() == DialogResult.OK) {
                pnlTileset.Controls.Clear();
                string mapPath = dlg.FileName;
                loadMap(mapPath);
                mapOpened = true;
            }
        }
        private void readTileset(ResourceReader resr) {
            Dictionary<String, PictureBox> tileset = new Dictionary<string, PictureBox>();
            IDictionaryEnumerator en = resr.GetEnumerator();
            MemoryStream ms;
            byte[] data;
            string type;
            while (en.MoveNext()) {
                string key = (string)en.Key;
                resr.GetResourceData(key, out type, out data);
                if (type.Equals("png")) {
                    PictureBox pb = new PictureBox();
                    pb.Click += new EventHandler(pb_Click);
                    pb.SizeMode = PictureBoxSizeMode.StretchImage;
                    pb.Height = 32;
                    pb.Width = 32;
                    ms = new MemoryStream(data);
                    pb.Image = Bitmap.FromStream(ms);
                    tileset.Add(key, pb);
                }
            }

            for (int i = 0; i < tileset.Count; i++) {
                pnlTileset.Controls.Add(tileset["" + i]);
            }

            resr.GetResourceData("tileset", out type, out data);
            tds.Clear();
            ms = new MemoryStream(data);
            tds.ReadXml(ms);
            ms.Close();
        }
        private void readMapContent(ResourceReader resr) {
            byte[] data;
            string type;
            resr.GetResourceData("content", out type, out data);
            wds.Clear();
            MemoryStream ms = new MemoryStream(data);
            wds.ReadXml(ms);
            ms.Close();
        }
        private void readMapData(ResourceReader resr) {
            byte[] data;
            string type;
            resr.GetResourceData("mapdata", out type, out data);
            MemoryStream ms = new MemoryStream(data);
            BinaryReader br = new BinaryReader(ms);

            br.ReadInt32(); // 0x3150414D
            name = br.ReadString(); //Name der Map
            br.ReadInt16(); //Tileset-ID
            money = br.ReadInt32(); //Start-Geld
            _startfield.x = br.ReadInt32(); //Startfeld
            _startfield.y = br.ReadInt32();
            _endfield.x = br.ReadInt32(); //Zielfeld
            _endfield.y = br.ReadInt32();
            int height = br.ReadInt32(); //Höhe
            int width = br.ReadInt32(); //Breite

            _Fields = new byte[height, width];

            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    _Fields[y, x] = br.ReadByte();
                }
            }
            drawMap();
            br.Close();
            ms.Close();
        }

        private void loadMap(string mapPath)
        {
            this.mapPath = mapPath;
            FileStream fs = new FileStream(mapPath, FileMode.Open);
            ResourceReader resr = new ResourceReader(fs);
            readTileset(resr);
            readMapContent(resr);
            readMapData(resr);
            fs.Close();

            selectedTile = null;
            pnlMap.Enabled = true;
            mnuMapSpeichern.Enabled = true;

            fillTextBoxes();

            btnTilesetBearbeiten.Enabled = true;
        }

        private void fillTextBoxes() {
            txtName.Text = name; txtName.ReadOnly = false;
            txtMoney.Text = "" + money; txtMoney.ReadOnly = false;
            txtStartX.Text = "" + _startfield.x; txtStartX.ReadOnly = false;
            txtStartY.Text = "" + _startfield.y; txtStartY.ReadOnly = false;
            txtEndX.Text = "" + _endfield.x; txtEndX.ReadOnly = false;
            txtEndY.Text = "" + _endfield.y; txtEndY.ReadOnly = false;
            txtHeight.Text = "" + _Fields.GetLength(0);
            txtWidth.Text = "" + _Fields.GetLength(1);
        }
        private void writeTileset(ResourceWriter resw) {
            MemoryStream ms;
            for (int i = 0; i < pnlTileset.Controls.Count; i++) {
                ms = new MemoryStream();
                ((PictureBox)pnlTileset.Controls[i]).Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                resw.AddResourceData("" + i, "png", ms.ToArray());
            }
            ms = new MemoryStream();
            tds.WriteXml(ms);
            resw.AddResourceData("tileset", "xml", ms.ToArray());
        }
        private void writeMapContent(ResourceWriter resw) {
            MemoryStream ms = new MemoryStream();
            wds.WriteXml(ms);
            resw.AddResourceData("content", "xml", ms.ToArray());
        }
        private void writeMapData(ResourceWriter resw) {
            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)0x3150414D);

            bw.Write(name); //Name der Map
            bw.Write((short)0); //Tileset-ID
            bw.Write((int)money); //Start-Geld
            bw.Write((int)_startfield.x); //Startfeld
            bw.Write((int)_startfield.y);
            bw.Write((int)_endfield.x); //Zielfeld
            bw.Write((int)_endfield.y);
            bw.Write((int)MapHeight); //Höhe
            bw.Write((int)MapWidth); //Breite
            for (int y = 0; y < MapHeight; y++) {
                for (int x = 0; x < MapWidth; x++) {
                    bw.Write((byte)_Fields[y, x]);
                }
            }
            resw.AddResourceData("mapdata", "map", ms.ToArray());
            bw.Close();
            ms.Close();
        }

        private void saveMap(string path) {
            FileStream fs = new FileStream(path, FileMode.Create);
            ResourceWriter resw = new ResourceWriter(fs);
            writeTileset(resw);
            writeMapContent(resw);
            writeMapData(resw);
            resw.Close();
        }

        private void mnuMapSpeichern_Click(object sender, EventArgs e) {
            if (wds.Towers.Rows.Count == 0) {
                MessageBox.Show("Auf dieser Map sind keine Tower verfügbar. Bitte erstelle zuerst mindestens einen Tower", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (wds.Creeps.Rows.Count == 0) {
                MessageBox.Show("Auf dieser Map gibt es keine Creeps. Bitte erstelle zuerst mindestens einen Creep und eine Wave", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (wds.Waves.Rows.Count == 0) {
                MessageBox.Show("Auf dieser Map gibt es keine Waves. Bitte erstelle zuerst mindestens eine Wave", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = "Map (*.map)|*.map";
            if (dlg.ShowDialog() == DialogResult.OK) {
                saveMap(dlg.FileName);
            }
        }

        private void Form1_Load(object sender, EventArgs e) {
            ToolTip t = new ToolTip();
            t.SetToolTip(txtStartX, "x");
            t.SetToolTip(txtStartY, "y");
            t.SetToolTip(txtEndX, "x");
            t.SetToolTip(txtEndY, "y");

            twEdit = new TowerEdit(wds);
            crEdit = new CreepEdit(wds);
            wvEdit = new WaveEdit(wds);

            twEdit.FormClosed += new FormClosedEventHandler(twEdit_FormClosed);
            crEdit.FormClosed += new FormClosedEventHandler(crEdit_FormClosed);
            wvEdit.FormClosed += new FormClosedEventHandler(wvEdit_FormClosed);
        }

        void wvEdit_FormClosed(object sender, FormClosedEventArgs e)
        {
            wvEditOpen = false;
        }

        void crEdit_FormClosed(object sender, FormClosedEventArgs e)
        {
            crEditOpen = false;
        }

        void twEdit_FormClosed(object sender, FormClosedEventArgs e)
        {
            twEditOpen = false;
        }

        private void setTile(PictureBox tile, int x, int y) {
            Graphics g = Graphics.FromImage(picMap.Image);
            g.DrawImage(tile.Image, new Rectangle(x * 32, y * 32, 32, 32), 0, 0, tile.Image.Width, tile.Image.Height, GraphicsUnit.Pixel);
            _Fields[y, x] = (byte)pnlTileset.Controls.IndexOf(tile);
            drawGrid(g);
            picMap.Refresh();
        }

        private void setStartField(int x, int y) {
            Graphics g = Graphics.FromImage(picMap.Image);
            if (pnlTileset.Controls.Count > 0) {
                Image tile = ((PictureBox)pnlTileset.Controls[_Fields[_startfield.y, _startfield.x]]).Image;
                g.DrawImage(tile, new Rectangle(_startfield.x * 32, _startfield.y * 32, 32, 32), 0, 0, tile.Width, tile.Height, GraphicsUnit.Pixel);
            } else {
                g.FillRectangle(new SolidBrush(pnlMap.BackColor), _startfield.x * 32, _startfield.y * 32, 32, 32);
            }
            _startfield.x = x;
            _startfield.y = y;

            g.FillRectangle(new SolidBrush(Color.FromArgb(95, Color.Green)), _startfield.x * 32, _startfield.y * 32, 32, 32);
            drawGrid(g);
            picMap.Refresh();
        }

        private void setEndField(int x, int y) {
            Graphics g = Graphics.FromImage(picMap.Image);
            if (pnlTileset.Controls.Count > 0) {
                Image tile = ((PictureBox)pnlTileset.Controls[_Fields[_endfield.y, _endfield.x]]).Image;
                g.DrawImage(tile, new Rectangle(_endfield.x * 32, _endfield.y * 32, 32, 32), 0, 0, tile.Width, tile.Height, GraphicsUnit.Pixel);
            } else {
                g.FillRectangle(new SolidBrush(pnlMap.BackColor), _endfield.x * 32, _endfield.y * 32, 32, 32);
            }
            _endfield.x = x;
            _endfield.y = y;

            g.FillRectangle(new SolidBrush(Color.FromArgb(95, Color.Red)), _endfield.x * 32, _endfield.y * 32, 32, 32);
            drawGrid(g);
            picMap.Refresh();
        }

        private void txtStartX_TextChanged(object sender, EventArgs e) {
            try {
                if (!txtStartY.Text.Equals("")) {
                    int x = Int32.Parse(txtStartX.Text);
                    int y = Int32.Parse(txtStartY.Text);
                    if (x < 0 || y < 0 || x >= MapWidth || y >= MapHeight) throw new Exception();
                    setStartField(x, y);
                    txtStartX.BackColor = System.Drawing.SystemColors.Window;
                }
            }
            catch (Exception ex) {
                txtStartX.BackColor = Color.Red;
            }
            
        }

        private void txtStartY_TextChanged(object sender, EventArgs e) {
            try {
                if (!txtStartX.Text.Equals("")) {
                    int x = Int32.Parse(txtStartX.Text);
                    int y = Int32.Parse(txtStartY.Text);
                    if (x < 0 || y < 0 || x >= MapWidth || y >= MapHeight) throw new Exception();
                    setStartField(x, y);
                    txtStartY.BackColor = System.Drawing.SystemColors.Window;
                }
            }
            catch (Exception ex) {
                txtStartY.BackColor = Color.Red;
            }
        }

        private void txtEndX_TextChanged(object sender, EventArgs e) {
            try {
                if (!txtEndY.Text.Equals("")) {
                    int x = Int32.Parse(txtEndX.Text);
                    int y = Int32.Parse(txtEndY.Text);
                    if (x < 0 || y < 0 || x >= MapWidth || y >= MapHeight) throw new Exception();
                    setEndField(x, y);
                    txtEndX.BackColor = System.Drawing.SystemColors.Window;
                }
            }
            catch (Exception ex) {
                txtEndX.BackColor = Color.Red;
            }
        }

        private void txtEndY_TextChanged(object sender, EventArgs e) {
            try {
                if (!txtEndX.Text.Equals("")) {
                    int x = Int32.Parse(txtEndX.Text);
                    int y = Int32.Parse(txtEndY.Text);
                    if (x < 0 || y < 0 || x >= MapWidth || y >= MapHeight) throw new Exception();
                    setEndField(x, y);
                    txtEndY.BackColor = System.Drawing.SystemColors.Window;
                }
            }
            catch (Exception ex) {
                txtEndY.BackColor = Color.Red;
            }
        }

        private void txtName_TextChanged(object sender, EventArgs e) {
            if (txtName.Text.Equals("")) {
                txtName.BackColor = Color.Red;
            } else {
                name = txtName.Text;
                txtName.BackColor = System.Drawing.SystemColors.Window;
            }
        }

        private void txtMoney_TextChanged(object sender, EventArgs e) {
            try {
                money = Int32.Parse(txtMoney.Text);
                if (money < 0) throw new Exception();
                txtMoney.BackColor = System.Drawing.SystemColors.Window;
            }
            catch (Exception ex) {
                txtMoney.BackColor = Color.Red;
            }
        }

        private void txtHeight_TextChanged(object sender, EventArgs e) {

        }

        private void txtWidth_TextChanged(object sender, EventArgs e) {

        }

        private void towerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (twEditOpen)
                twEdit.BringToFront();
            else
            {
                if (twEdit.IsDisposed)
                {
                    twEdit = new TowerEdit(wds);
                    twEdit.FormClosed += new FormClosedEventHandler(twEdit_FormClosed);
                }
                twEdit.FileName = mapPath;
                twEdit.Show();
                twEditOpen = true;
            }
            
        }

        private void creepsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (crEditOpen)
                crEdit.BringToFront();
            else
            {
                if (crEdit.IsDisposed)
                {
                    crEdit = new CreepEdit(wds);
                    crEdit.FormClosed += new FormClosedEventHandler(crEdit_FormClosed);
                }
                crEdit.FileName = mapPath;
                crEdit.Show();
                crEditOpen = true;
            }
        }

        private void Form1_Activated(object sender, EventArgs e)
        {

            if(!disclaimerShown) {
                disclaimerShown = true;
                Disclaimer disclaimer = new Disclaimer();
                disclaimer.ShowDialog();
            }
        }

        private void wavesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (wvEditOpen)
                wvEdit.BringToFront();
            else
            {
                if (wvEdit.IsDisposed)
                {
                    wvEdit = new WaveEdit(wds);
                    wvEdit.FormClosed += new FormClosedEventHandler(wvEdit_FormClosed);
                }
                wvEdit.FileName = mapPath;
                wvEdit.Show();
                wvEditOpen = true;
            }
        }

        private void btnTilesetBearbeiten_Click(object sender, EventArgs e)
        {
            Image[] tiles = new Image[pnlTileset.Controls.Count];
            for (int i = 0; i < pnlTileset.Controls.Count; i++) {
                tiles[i] = ((PictureBox)pnlTileset.Controls[i]).Image;
            }
            TilesetEditor tEdit = new TilesetEditor(tds, tiles, _Fields);
            tEdit.ShowDialog();
            pnlTileset.Controls.Clear();
            for (int i = 0; i < tEdit.Tileset.Length; i++) {
                PictureBox pb = new PictureBox();
                pb.Click += new EventHandler(pb_Click);
                pb.SizeMode = PictureBoxSizeMode.StretchImage;
                pb.Height = 32;
                pb.Width = 32;
                pb.Image = tEdit.Tileset[i];
                pnlTileset.Controls.Add(pb);
            }
            drawMap();
            //tEdit.Tileset
            /*tEdit.TilesetResource = tilesetBuffer;
            tEdit.ShowDialog();
            tilesetBuffer = tEdit.TilesetResource;
            Dictionary<String, PictureBox> tileset = new Dictionary<string, PictureBox>();

            pnlTileset.Controls.Clear();

            ResourceReader resr = new ResourceReader(new MemoryStream(tEdit.TilesetResource));
            IDictionaryEnumerator en = resr.GetEnumerator();
            byte[] tile;
            while (en.MoveNext())
            {
                string type;
                string key = (string)en.Key;
                resr.GetResourceData(key, out type, out tile);
                if (type.Equals("png"))
                {
                    PictureBox pb = new PictureBox();
                    pb.Click += new EventHandler(pb_Click);
                    pb.SizeMode = PictureBoxSizeMode.AutoSize;
                    MemoryStream ms = new MemoryStream(tile);
                    pb.Image = Bitmap.FromStream(ms);
                    tileset.Add(key, pb);
                }
            }

            for (int i = 0; i < tileset.Count; i++)
            {
                pnlTileset.Controls.Add(tileset["" + i]);
            }*/
        }

        private void mnuNeueMap_Click(object sender, EventArgs e)
        {
            if (mapOpened) {
                if (MessageBox.Show("Es ist bereits eine Map geöffnet.\nMöchtest du trotzdem eine neue Map erstellen?\n\nAlle ungespeicherten Änderungen gehen dabei verloren!", "Neue Map", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) {
                    return;
                }
            }
            NeueMap nMap = new NeueMap();
            if (nMap.ShowDialog() == DialogResult.OK) {
                _Fields = new byte[nMap.MapHeight, nMap.MapWidth];
                _startfield.x = 0;
                _startfield.y = 0;
                _endfield.x = 1;
                _endfield.y = 0;
                name = nMap.MapName;
                money = nMap.Money;
                pnlTileset.Controls.Clear();
                tds = new TilesetDS();
                wds = new WavesDS();
                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                MemoryStream ms = new MemoryStream(enc.GetBytes(PokeTD_MapEditor.Properties.Resources.DefaultWaves));
                wds.ReadXml(ms);

                btnTilesetBearbeiten_Click(null, EventArgs.Empty);

                selectedTile = null;
                pnlMap.Enabled = true;
                mnuMapSpeichern.Enabled = true;
                btnTilesetBearbeiten.Enabled = true;
                fillTextBoxes();
                mapOpened = true;
            }
        }

        private void datenImportierenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Beim Import wird die bisherige Datenbank gelöscht!\nFortfahren?", "Frage", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.AddExtension = true;
                ofd.Filter = "*.xml|XML-Dateien|*.*|Alle Dateien";
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    wds.Clear();
                    wds.ReadXml(ofd.FileName);
                }
            }
        }

        private void datenexpotierenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.AddExtension = true;
            sfd.Filter = "*.xml|XML-Dateien|*.*|Alle Dateien";
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                wds.WriteXml(sfd.FileName);
            }
        }

        private void mnuBeenden_Click(object sender, EventArgs e) {
            this.Close();
        }

        private void mnuMapImportieren_Click(object sender, EventArgs e) {
            if (mapOpened) {
                if (MessageBox.Show("Es ist bereits eine Map geöffnet.\nMöchtest du trotzdem eine Map importieren?\n\nAlle ungespeicherten Änderungen gehen dabei verloren!", "Map importieren", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) {
                    return;
                }
            }
            MapImport impMap = new MapImport();
            if (impMap.ShowDialog() == DialogResult.OK) {
                Image img = Bitmap.FromFile(impMap.FileName);
                int tileHeight = impMap.TileHeight;
                int tileWidth = impMap.TileWidth;
                int mapHeight = img.Height/tileHeight;
                int mapWidth = img.Width/tileWidth;

                _Fields = new byte[mapHeight, mapWidth];
                _startfield.x = 0;
                _startfield.y = 0;
                _endfield.x = 1;
                _endfield.y = 0;
                name = impMap.MapName;
                money = impMap.Money;

                pnlTileset.Controls.Clear();
                tds = new TilesetDS();

                wds = new WavesDS();
                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                MemoryStream ms = new MemoryStream(enc.GetBytes(PokeTD_MapEditor.Properties.Resources.DefaultWaves));
                wds.ReadXml(ms);

                progressBar.Maximum = mapHeight * mapWidth;
                progressBar.Visible = true;
                List<PictureBox> pbList = new List<PictureBox>();
                for (int y = 0; y < MapHeight; y++) {
                    for (int x = 0; x < MapWidth; x++) {
                        Bitmap b = new Bitmap(tileWidth, tileHeight);
                        Graphics g = Graphics.FromImage(b);

                        g.DrawImage(img, new Rectangle(0, 0, tileWidth, tileHeight), new Rectangle(x * tileWidth, y * tileHeight, tileWidth, tileHeight), GraphicsUnit.Pixel);
                        g.Dispose();
                        int index = getTileIndex(b, pbList);
                        if (index == -1) {
                            if (pbList.Count < 256) {
                                PictureBox pb = new PictureBox();
                                pb.Click += new EventHandler(pb_Click);
                                pb.SizeMode = PictureBoxSizeMode.StretchImage;
                                pb.Height = 32;
                                pb.Width = 32;
                                pb.Image = b;
                                _Fields[y, x] = (byte)pbList.Count;
                                tds.Tile.AddTileRow(pbList.Count, true);
                                pbList.Add(pb);
                                progressBar.PerformStep();
                            } else {
                                progressBar.PerformStep();
                            }
                        } else {
                            _Fields[y, x] = (byte)index;
                            progressBar.PerformStep();
                        }
                    }
                }
                pnlTileset.Controls.AddRange(pbList.ToArray());
                progressBar.Value = 0;
                progressBar.Visible = false;
                drawMap();
                selectedTile = null;
                pnlMap.Enabled = true;
                mnuMapSpeichern.Enabled = true;
                btnTilesetBearbeiten.Enabled = true;
                fillTextBoxes();
                mapOpened = true;
            }
        }

        private int getTileIndex(Image bmp, List<PictureBox> pbList) {
            ImageConverter ic = new ImageConverter();
            for (int i = 0; i < pbList.Count; i++) {
                byte[] btImage1 = new byte[1];
                btImage1 = (byte[])ic.ConvertTo(bmp, btImage1.GetType());

                Image bmp2 = pbList[i].Image;
                byte[] btImage2 = new byte[1];
                btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());

                SHA256Managed shaM = new SHA256Managed();
                byte[] hash1 = shaM.ComputeHash(btImage1);
                byte[] hash2 = shaM.ComputeHash(btImage2);
                bool same = true;
                if (hash1.Length == hash2.Length) {
                    for (int n = 0; n < hash1.Length; n++) {
                        if (hash1[n] != hash2[n]) {
                            same = false;
                            break;
                        }
                    }
                    if (same) return i;
                }
            }
            return -1;
        }
    }
}
